Nonterminals 
	form
	request response
	request_line status_line headers 
	request_uri request_rel_uri net_path abs_path path_segments query query_segments segment
	text istring
	.
Terminals 
	integer string '/' ':' version '?' '&' '=' body header scheme
	.
Rootsymbol form.

form -> request : '$1'.
form -> response : '$1'.


request -> request_line headers body : 
	{Method,URI,Version} = '$1',
	#req{method=Method,uri=URI,version=Version,headers=lists:flatten('$2'),body=value_of('$3')}.
request -> request_line headers : 
	{Method,URI,Version} = '$1',
	#req{method=Method,uri=URI,version=Version,headers=lists:flatten('$2')}.
request -> request_line :  
	{Method,URI,Version} = '$1',
	#req{method=Method,uri=URI,version=Version}.


response -> status_line headers body : 
	{Version,Status,Reason} = '$1',
	#res{version=Version,status=Status,reason=Reason,headers = lists:flatten('$2'),entity = value_of('$3')}.
response -> status_line headers : 
	{Version,Status,Reason} = '$1',
	#res{version=Version,status=Status,reason=Reason,headers = lists:flatten('$2')}.
response -> status_line : 
	{Version,Status,Reason} = '$1',
	#res{version=Version,status=Status,reason=Reason}.

request_line -> string request_uri version : {v('$1'),'$2',value_of('$3')}.
request_line -> string request_rel_uri version : {v('$1'),'$2',value_of('$3')}.


status_line -> version integer text : {value_of('$1'),value_of('$2'),lists:flatten('$3')}.

headers -> header text : [{v('$1'),lists:flatten('$2')}].
headers -> header text headers : [{v('$1'),lists:flatten('$2')},'$3'].

request_uri -> scheme ':' net_path abs_path '?' query : #uri{scheme=v('$1'),net_path='$3',abs_path='$4',uri_query='$6',type=abs}.
request_uri -> scheme ':' net_path abs_path : #uri{scheme=v('$1'),net_path='$3',abs_path='$4',type=abs}.
request_uri -> scheme ':' net_path : #uri{scheme=v('$1'),net_path='$3',type=abs}.


request_rel_uri -> abs_path '?' query : #uri{abs_path='$1',uri_query='$2',type=rel}.
request_rel_uri -> abs_path : #uri{abs_path='$1',type=rel}.


net_path -> '/' '/' string : value_of('$3').

abs_path -> path_segments : lists:flatten('$1').

path_segments -> '/' : [token_to_list('$1')].
path_segments -> '/' istring : [token_to_list('$1'),'$2'].
path_segments -> '/' istring path_segments : [token_to_list('$1'),'$2','$3'].

query -> query_segments : lists:flatten('$1').

query_segments -> segment : ['$1'].
query_segments -> segment '&' query_segments : ['$1','$3'].

segment -> string '=' istring : {v('$1'),'$3'}.


istring -> string : value_of('$1').
istring -> integer : integer_to_list(value_of('$1')).

text -> istring : '$1'.
text -> istring text : ['$1',[32],'$2'].





Erlang code.

-include("http.hrl").

token_to_list(Token) -> atom_to_list(element(1,Token)).


value_of(Token) -> element(2,Token).

v({_Type,Value}) -> v(Value);
v(Token) ->
	case string:to_integer(Token) of
		{error,not_a_list} -> Value = Token;
		{error,_Reason} -> Value = list_to_atom(http_util:to_lower(Token));
		{Value,_} -> ok
	end,
	case Value of
		Value when is_atom(Value) -> Value;
		Value when is_list(Value) -> list_to_atom(http_util:to_lower(Value));
		Value when is_integer(Value) -> Value
	end.